package com.qf.listener;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.config.DelayedConfig;
import com.qf.constant.CacheConstants;
import com.qf.constant.RabbitMQConstants;
import com.qf.feign.CacheFeign;
import com.qf.model.StandardReport;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.Date;
import java.util.Map;

/**
 *
 * 监听短信发送状态报告, 推送给第三方用户(JD客户端或icbc客户端）
 * @author wuziyu
 */
@Component
@Slf4j
public class PushSmsReportListener {

    @Autowired
    private CacheFeign cacheFeign;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    //时间数组 TTL time to live
    // 状态报告发送次数和时间: 1,2,3,4,5    立即推送,10s之后， 30s之后， 1min， 5min
    //毫秒
    private Integer[] sendTTl = {0,10000,30000,60000,300000};
    /**
     *  接收延迟消息的   监听短信发送状态报告
     * @param channel
     * @param message
     * @throws Exception
     * //推送状态报告TOPIC    ---      让接口模块给客户端一个推送.
     */
    @RabbitListener(queues = RabbitMQConstants.TOPIC_PUSH_SMS_REPORT)
    public void listenerPushSmsReport(Message message, Channel channel, StandardReport standardReport){
        try {
            //1:接口模块之前发送消息的时候  //StandardSubmit 就有分布式ID
            //2:接口模块接收之前的短信报告
            //standardReport; ： 唯一的序列标识 ： 证明是你之前接收的StandardSubmit报告
            //3:推送报告给用户
            //3.1:校验用户是否需要推送报告m
            long clientID = standardReport.getClientID();
            Map map = cacheFeign.hMGet(CacheConstants.CACHE_PREFIX_CLIENT + clientID);
            if (!"1".equals(String.valueOf(map.get("isreturnstatus")))){
                //客户表示  不需要发推送报告  什么也不干  直接应答返回   1是需要发送
                //手动应答
                channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
                return;
            }
            //客户表示  需要发推送报告
            //状态报告发送次数和时间: 1,2,3,4,5    立即推送,10s之后， 30s之后， 1min， 5min
            Object receivestatusurl = map.get("receivestatusurl");
            String result = sendStatusReport(receivestatusurl, standardReport);
            if (null==result){
                channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
                return;
            }
            isSuccess(result,standardReport);
            //手动应答
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (Exception e) {
//            e.printStackTrace();
            if (message.getMessageProperties().isRedelivered()){
                try {
                    log.error("接收推送用户的报告消息失败了:{}",objectMapper.writeValueAsString(standardReport));
                    //转人工
                    channel.basicReject(message.getMessageProperties().getDeliveryTag(),false);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }else {
                //第一次接收消息
                try {
                    channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
    }
    //判断远程调用 返回值结果是否是成功 还是失败
    private void isSuccess(String result,StandardReport standardReport) {
        if (!"SUCCESS".equalsIgnoreCase(result)){
            //失败
            //状态报告发送次数和时间: 1,2,3,4,5    立即推送,10s之后， 30s之后， 1min， 5min
            // 使用延迟消息队列  来 重新给用户推荐报告
            rabbitTemplate.convertAndSend(
                    DelayedConfig.DELAYED_EXCHANGE,"routingKey",standardReport,message -> {
                        //延迟时间  sendTTL 通过发送的次数获取对应的延迟时间
                        message.getMessageProperties().setDelay(sendTTl[standardReport.getSendCount()]);
                        return message;
                    }
            );
        }
    }


    public String sendStatusReport(Object receivestatusurl,StandardReport standardReport){
        //参数1  url  客户的回调路径
    //参数二  request对象
    //请求头
    String result = null;
    try {
        int sendCount = standardReport.getSendCount();
        if (sendCount >=5){
            //打印日志
            log.error(
                    "用户推荐报告已经推送五次以上还是不成功：报告是：{}",
                    objectMapper.writeValueAsString(standardReport)
            );
            //转人工
            return  null;
        }
        sendCount++;
        standardReport.setSendCount(sendCount);
        HttpHeaders httpHeaders = new HttpHeaders();
        //请求头中指定传送数据的类型  JSON  类型
        httpHeaders.setContentType(MediaType.APPLICATION_PROBLEM_JSON_UTF8);
        //请求体
        HttpEntity<String> httpEntity=new HttpEntity<String>(
                objectMapper.writeValueAsString(standardReport),//请求体
                httpHeaders);//请求头
        //参数三  响应类型
        result = restTemplate.postForObject(
                String.valueOf(receivestatusurl),
                httpEntity,
                String.class);
    } catch (Exception e) {
        //状态报告发送次数和时间: 1,2,3,4,5    立即推送,10s之后， 30s之后， 1min， 5min
        // 使用延迟消息队列  来 重新给用户推荐报告
        rabbitTemplate.convertAndSend(
                DelayedConfig.DELAYED_EXCHANGE,"routingKey",standardReport,message -> {
                    //延迟时间  sendTTL 通过发送的次数获取对应的延迟时间
                    message.getMessageProperties().setDelay(sendTTl[standardReport.getSendCount()]);
                    return message;
                });
    return null;
    }
    return result;
}

    /*
    接收延迟对象中消息 重新给用户推荐报告
     */

    @RabbitListener(queues = DelayedConfig.DELAYED_QUEUE)
    public void replayPushSmsReport(Message message, Channel channel, StandardReport standardReport) {

        //用户推荐报告
        String result = sendStatusReport(standardReport.getReceiveStatusUrl(), standardReport);
        if (null==result){
            try {
                channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return;
        }
        try {
            // //远程调用成功  返回值不一定是成功  success（成功）     |||||  fail或是其它 (失败）
            isSuccess(result,standardReport);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}











//    @RabbitListener(queues = "delayed_queue")
///*    public void receiverDelayMessage(StandardReport standardReport,
//                                     Channel channel, Message message) throws Exception{*/
//    public void receiverDelayMessage(String msg,
//                                     Channel channel, Message message) throws Exception{
//
//        //standardReport  : 推送给第三方用户(JD客户端或icbc客户端）
//        System.out.println("===接收到了推送给第三方用户(JD客户端或icbc客户端）报告" + new Date() + ":" + msg);
//        //手动应答
//        //channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
//
//    }
